import cgi
import os
import re
import urllib
import urlparse
import mimetypes
import xpath
from xml.dom import minidom

from xml.sax import saxutils 
from django.utils import simplejson 
from google.appengine.api import urlfetch
from google.appengine.api.urlfetch import DownloadError 
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class FFOPML(webapp.RequestHandler): 
  @staticmethod
  def getRequestParams(requestQueryString, paramsList):
    requestQueryString = "&" + requestQueryString
    paramIndexes = [(param, requestQueryString.find('&' + param + '=')) for param in paramsList]
    paramIndexes = sorted(filter(lambda x: x[1]!=-1, paramIndexes),key=lambda x:x[1])
    paramIndexes = [(paramIndexes[i][0], paramIndexes[i][1] + len(paramIndexes[i][0]) + 2, len(requestQueryString) if (i == (len(paramIndexes)-1)) else paramIndexes[i+1][1])
                    for i in range(len(paramIndexes))]
    return dict((param[0], urllib.unquote(requestQueryString[param[1]:param[2]])) for param in paramIndexes)

  @staticmethod
  def fetchContent(contentUrl, maxRetryCount=2, maxTimeout=10):
    contentUrl = contentUrl.replace(" ", "%20")
    for i in range(maxRetryCount):
      try: 
        fetchResult = urlfetch.fetch(contentUrl, deadline=maxTimeout)
        break
      except DownloadError: 
        fetchResult = None
    if not(fetchResult) or fetchResult.status_code != 200:
      return None
    else:
      return fetchResult.content
  
  @staticmethod
  def fetchContentDOM(contentUrl):
    contentString = FFOPML.fetchContent(contentUrl)
    return minidom.parseString(contentString)
    
  @staticmethod
  def fetchContentJSON(contentUrl):
    contentString = FFOPML.fetchContent(contentUrl)
    return simplejson.loads(contentString)
    
  @staticmethod
  def isOPML(opmlDom):
    rootTagName = opmlDom.documentElement.localName
    return rootTagName.lower() == "opml"
  
  def parseOPML(self, opmlUrl):
    contentString = FFOPML.fetchContent(opmlUrl)
    opmlDom = minidom.parseString(contentString)

    if not(FFOPML.isOPML(opmlDom)):
      return None

    opmlItems = xpath.find('//*[local-name() = "outline" and @xmlUrl]', opmlDom.documentElement)

    opmlUrls = []
    for opmlItem in opmlItems:
      itemType = opmlItem.getAttribute('type')
      itemUrl = opmlItem.getAttribute('xmlUrl')
      itemTitle = opmlItem.getAttribute('title')
      opmlUrls += [{'title' : itemTitle, 'url' : itemUrl, 'type' : itemType }]
    
    return opmlUrls
  
  # FF mechanized script in ruby:
  # http://github.com/knu/ruby-friendfeed/blob/01815b113d4b0f06602ac390b4769d102bfd53af/lib/friendfeed/unofficial.rb
  
  '''
    # Creates a new feed of a given (unique) +nickname+ and display
    # +name+, and returns a unique ID string on success.  The +type+
    # can be one of "group", "microblog" and "public".  Like other
    # methods in general, an exception is raised on
    # failure. [unofficial]
   def create_group(nickname, name, type = 'group'):
      apiCallUrl = 'http://friendfeed.com/a/createfeed?nickname=%s&name=%s&type=%s'
      post(ROOT_URI + '/a/createfeed', 'nickname' => nickname, 'name' => name, 'type' => type).xpath("(//a[@class='l_feedinvite'])[1]/@sid").to_s
      return
    
        # Adds a feed to the authenticated user or a group specified by a
    # unique ID.  Specify 'isstatus' => 'on' to display entries as
    # messages (no link), and 'importcomment' => 'on' to include entry
    # description as a comment. [unofficial]
    def add_service(id, service, options = nil)
      params = {
        'stream' => id,
        'service' => service,
      }
      params.update(options) if options
      post(ROOT_URI + '/a/configureservice', params)
    end
 
        # Adds a feed to the authenticated user or a group specified by a
    # unique ID.  Specify 'isstatus' => 'on' to display entries as
    # messages (no link), and 'importcomment' => 'on' to include entry
    # description as a comment. [unofficial]
    def add_feed(id, url, options = nil)
      params = { 'url' => url }
      params.update(options) if options
      add_service(id, 'feed', options)
    end
  '''
  
  # python mechanize library and twill extension:
  # http://wwwsearch.sourceforge.net/mechanize/
  # http://twill.idyll.org/python-api.html
  
  def importOPML(self, opml, group, comment, message, username, password, remotekey):
    # get opml 
    # check if room exists
    # if room does not exist - create
    # add feeds as custom rss feeds with options
    
    # icons:
    # http://opml.us/images/opml-icon.jpg
    # http://i.friendfeed.com/37829cd45442053ec5ec3462121dc79845fff8c3
    # http://practicumpioneers.files.wordpress.com/2009/02/friendfeed.jpg
  
  def get(self):
    requestParams = FFOPML.getRequestParams(self.request.query_string, ['opmlUrl']) 
    opmlItems = self.parseOPML(requestParams['opmlUrl'])
    
    #feedUrl = self.filterFeedUrl(requestParams['inputFeedUrl'])
    # check if ff room/imaginary friend exists
    # for each url - add url to room/friend as custom rss/atom service
    http://friendfeed.com/api/room/friendfeed-news/profile
    http://friendfeed.com/api/room/friendfeed-news/subscribe
    
    self.response.out.write(str(opmlItems))
    return

application = webapp.WSGIApplication([('/ffopml.*', FFOPML)], debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()